//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software 
// is granted provided this copyright notice appears in all copies. 
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
//          mcseemagg@yahoo.com
//          http://www.antigrain.com
//----------------------------------------------------------------------------
//
// classes rbox_ctrl_impl, rbox_ctrl
//
//----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using AGG.VertexSource;

namespace AGG.UI
{
    //------------------------------------------------------------------------
    public class rbox_ctrl_impl : SimpleVertexSourceWidget
    {
        public delegate void SelectionChangedEventHandler(object sender, MouseEventArgs mouseEvent);
        public event SelectionChangedEventHandler SelectionChanged;

        double m_border_width;
        double          m_border_extra;
        double          m_text_thickness;
        double          m_text_height;
        double          m_text_width;
        List<string> m_items;
        int             m_cur_item;

        double   m_xs1;
        double   m_ys1;
        double   m_xs2;
        double   m_ys2;

        double[]   m_vx = new double[32];
        double[]   m_vy = new double[32];
        int m_draw_item;
        double   m_dy;

        VertexSource.Ellipse               m_ellipse;
        conv_stroke  m_ellipse_poly;
        gsv_text              m_text;
        conv_stroke m_text_poly;

        int m_idx;
        int m_vertex;

        public rbox_ctrl_impl(double x1, double y1, double x2, double y2)
            : base (x1, y1, x2, y2)
        {
            m_border_width=(1.0);
            m_border_extra=(0.0);
            m_text_thickness=(1.5);
            m_text_height=(9.0);
            m_text_width=(0.0);
            m_cur_item=(-1);
            m_ellipse = new VertexSource.Ellipse();
            m_ellipse_poly = new conv_stroke(m_ellipse);
            m_text = new gsv_text();
            m_text_poly = new conv_stroke(m_text);
            m_idx=(0);
            m_vertex=(0);
            m_items = new List<string>();
            calc_rbox();
        }

        public void border_width(double t)
        {
            border_width(t, 0.0);
        }

        public void border_width(double t, double extra)
        { 
            m_border_width = t; 
            m_border_extra = extra;
            calc_rbox(); 
        }

        public void text_thickness(double t)  { m_text_thickness = t; }

        public void text_size(double h)
        {
            text_size(h, 0.0);
        }

        public void text_size(double h, double w)
        { 
            m_text_width = w; 
            m_text_height = h; 
        }

        public void add_item(string text)
        {
            m_items.Add(text);
        }

        public int  cur_item() { return m_cur_item; }
        public void cur_item(int i) { m_cur_item = i; }

        public override bool InRect(double x, double y)
        {
            Transform.inverse_transform(ref x, ref y);
            return Bounds.hit_test(x,y);
        }

        public override void OnMouseDown(MouseEventArgs mouseEvent)
        {
            double x = mouseEvent.X;
            double y = mouseEvent.Y;
            Transform.inverse_transform(ref x, ref y);
            int i;
            int NumItems = m_items.Count;
            for (i = 0; i < NumItems; i++)  
            {
                double xp = m_xs1 + m_dy / 1.3;
                double yp = m_ys1 + m_dy * i + m_dy / 1.3;
                if(agg_math.calc_distance(x, y, xp, yp) <= m_text_height / 1.5)
                {
                    m_cur_item = (int)(i);
                    Invalidate();
                    if(SelectionChanged != null)
                    {
                        SelectionChanged(this, mouseEvent);
                    }
                    return;
                }
            }
        }

        public override void OnKeyDown(KeyEventArgs keyEvent)
        {
            if(m_cur_item >= 0)
            {
                if (keyEvent.KeyCode == Keys.Up 
                    || keyEvent.KeyCode == Keys.Right)
                {
                    m_cur_item++;
                    if(m_cur_item >= m_items.Count)
                    {
                        m_cur_item = 0;
                    }
                    keyEvent.Handled = true;
                }

                if (keyEvent.KeyCode == Keys.Down 
                    || keyEvent.KeyCode == Keys.Left)
                {
                    m_cur_item--;
                    if(m_cur_item < 0)
                    {
                        m_cur_item = m_items.Count - 1;
                    }
                    keyEvent.Handled = true;
                }
            }
        }


        // Vertex source interface
        public override int num_paths() { return 5; }
        public override void rewind(int idx)
        {
            m_idx = idx;
            m_dy = m_text_height * 2.0;
            m_draw_item = 0;

            switch(idx)
            {
            default:

            case 0:                 // Background
                m_vertex = 0;
                m_vx[0] = Bounds.Left - m_border_extra;
                m_vy[0] = Bounds.Bottom - m_border_extra;
                m_vx[1] = Bounds.Right + m_border_extra;
                m_vy[1] = Bounds.Bottom - m_border_extra;
                m_vx[2] = Bounds.Right + m_border_extra;
                m_vy[2] = Bounds.Top + m_border_extra;
                m_vx[3] = Bounds.Left - m_border_extra;
                m_vy[3] = Bounds.Top + m_border_extra;
                break;

            case 1:                 // Border
                m_vertex = 0;
                m_vx[0] = Bounds.Left;
                m_vy[0] = Bounds.Bottom;
                m_vx[1] = Bounds.Right;
                m_vy[1] = Bounds.Bottom;
                m_vx[2] = Bounds.Right;
                m_vy[2] = Bounds.Top;
                m_vx[3] = Bounds.Left;
                m_vy[3] = Bounds.Top;
                m_vx[4] = Bounds.Left + m_border_width;
                m_vy[4] = Bounds.Bottom + m_border_width;
                m_vx[5] = Bounds.Left + m_border_width;
                m_vy[5] = Bounds.Top - m_border_width;
                m_vx[6] = Bounds.Right - m_border_width;
                m_vy[6] = Bounds.Top - m_border_width;
                m_vx[7] = Bounds.Right - m_border_width;
                m_vy[7] = Bounds.Bottom + m_border_width; 
                break;

            case 2:                 // Text
                m_text.text(m_items[0]);
                m_text.start_point(m_xs1 + m_dy * 1.5, m_ys1 + m_dy / 2.0);
                m_text.SetFontSize(m_text_height);
                m_text_poly.width(m_text_thickness);
                m_text_poly.line_join(math_stroke.line_join_e.round_join);
                m_text_poly.line_cap(math_stroke.line_cap_e.round_cap);
                m_text_poly.rewind(0);
                break;

            case 3:                 // Inactive items
                m_ellipse.init(m_xs1 + m_dy / 1.3, 
                               m_ys1 + m_dy / 1.3,
                               m_text_height / 1.5, 
                               m_text_height / 1.5, 32);
                m_ellipse_poly.width(m_text_thickness);
                m_ellipse_poly.rewind(0);
                break;


            case 4:                 // Active Item
                if(m_cur_item >= 0)
                {
                    m_ellipse.init(m_xs1 + m_dy / 1.3, 
                                   m_ys1 + m_dy * m_cur_item + m_dy / 1.3,
                                   m_text_height / 2.0, 
                                   m_text_height / 2.0, 32);
                    m_ellipse.rewind(0);
                }
                break;

            }
        }

        public override Path.FlagsAndCommand vertex(out double x, out double y)
        {
            x = 0;
            y = 0;
            Path.FlagsAndCommand cmd = Path.FlagsAndCommand.CommandLineTo;
            switch(m_idx)
            {
            case 0:
                if (m_vertex == 0) cmd = Path.FlagsAndCommand.CommandMoveTo;
                if (m_vertex >= 4) cmd = Path.FlagsAndCommand.CommandStop;
                x = m_vx[m_vertex];
                y = m_vy[m_vertex];
                m_vertex++;
                break;

            case 1:
                if (m_vertex == 0 || m_vertex == 4) cmd = Path.FlagsAndCommand.CommandMoveTo;
                if (m_vertex >= 8) cmd = Path.FlagsAndCommand.CommandStop;
                x = m_vx[m_vertex];
                y = m_vy[m_vertex];
                m_vertex++;
                break;

            case 2:
                cmd = m_text_poly.vertex(out x, out y);
                if(Path.is_stop(cmd))
                {
                    m_draw_item++;
                    if(m_draw_item >= m_items.Count)
                    {
                        break;
                    }
                    else
                    {
                        m_text.text(m_items[(int)m_draw_item]);
                        m_text.start_point(m_xs1 + m_dy * 1.5, 
                                           m_ys1 + m_dy * (m_draw_item + 1) - m_dy / 2.0);

                        m_text_poly.rewind(0);
                        cmd = m_text_poly.vertex(out x, out y);
                    }
                }
                break;

            case 3:
                cmd = m_ellipse_poly.vertex(out x, out y);
                if(Path.is_stop(cmd))
                {
                    m_draw_item++;
                    if(m_draw_item >= m_items.Count)
                    {
                        break;
                    }
                    else
                    {
                        m_ellipse.init(m_xs1 + m_dy / 1.3, 
                                       m_ys1 + m_dy * m_draw_item + m_dy / 1.3,
                                       m_text_height / 1.5, 
                                       m_text_height / 1.5, 32);
                        m_ellipse_poly.rewind(0);
                        cmd = m_ellipse_poly.vertex(out x, out y);
                    }
                }
                break;


            case 4:
                if(m_cur_item >= 0)
                {
                    cmd = m_ellipse.vertex(out x, out y);
                }
                else
                {
                    cmd = Path.FlagsAndCommand.CommandStop;
                }
                break;

            default:
                cmd = Path.FlagsAndCommand.CommandStop;
                break;
            }

            if(!Path.is_stop(cmd))
            {
                Transform.transform(ref x, ref y);
            }

            return cmd;
        }

        private void calc_rbox()
        {
            m_xs1 = Bounds.Left + m_border_width;
            m_ys1 = Bounds.Bottom + m_border_width;
            m_xs2 = Bounds.Right - m_border_width;
            m_ys2 = Bounds.Top - m_border_width;
        }
    };



    //------------------------------------------------------------------------
    public class RadioButtonWidget : rbox_ctrl_impl
    {
        IColorType m_background_color;
        IColorType m_border_color;
        IColorType m_text_color;
        IColorType m_inactive_color;
        IColorType m_active_color;

        public RadioButtonWidget(double x1, double y1, double x2, double y2) :
            base(x1, y1, x2, y2)
        {
            m_background_color=(new RGBA_Doubles(1.0, 1.0, 0.9));
            m_border_color=(new RGBA_Doubles(0.0, 0.0, 0.0));
            m_text_color=(new RGBA_Doubles(0.0, 0.0, 0.0));
            m_inactive_color=(new RGBA_Doubles(0.0, 0.0, 0.0));
            m_active_color=(new RGBA_Doubles(0.4, 0.0, 0.0));
        }
          

        public void background_color(IColorType c) { m_background_color = c; }
        public void border_color(IColorType c) { m_border_color = c; }
        public void text_color(IColorType c) { m_text_color = c; }
        public void inactive_color(IColorType c) { m_inactive_color = c; }
        public void active_color(IColorType c) { m_active_color = c; }

        public override IColorType color(int i) 
        {
            switch(i)
            {
                case 0:
                    return m_background_color;

                case 1:
                    return m_border_color;

                case 2:
                    return m_text_color;

                case 3:
                    return m_inactive_color;

                case 4:
                    return m_active_color;

                default:
                    throw new System.IndexOutOfRangeException("There is not a color for this index");
            }
        }
    };
}
